package com.gk.panda.apis.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gk.panda.apis.Vo.BiodiversityVo;
import com.gk.panda.apis.Vo.exports.ExportBiodiversityVO;
import com.gk.panda.apis.dto.BiodiversitySaveDto;
import com.gk.panda.apis.dto.BiodiversitySearchDto;
import com.gk.panda.apis.dto.imports.ImportBiodiversityDTO;
import com.gk.panda.apis.mapper.BiodiversityMapper;
import com.gk.panda.apis.service.*;
import com.gk.panda.apis.util.ListCopyUtils;
import com.gk.panda.apis.util.excel.ExcelUtils;
import com.gk.panda.commons.constant.Constants;
import com.gk.panda.commons.exception.ServerException;
import com.gk.panda.commons.util.UserUtil;
import com.gk.panda.pojo.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
public class BiodiversityImpl extends ServiceImpl<BiodiversityMapper, Biodiversity> implements BiodiversityService {

    private static final String TEMPLATE_ANIMAL_NAME = "动物名录导入模板.xlsx";
    private static final String TEMPLATE_BOTANY_NAME = "植物名录导入模板.xlsx";
    private static final String FILE_SUFFIX = ".xlsx";

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private OrgService orgService;

    @Autowired
    private BiologyFileService biologyFileService;

    @Autowired
    private RealtimeShootService realtimeShootService;

    /**
     * 分页查询生物名录
     * @param dto
     * @return
     */
    @Transactional(readOnly = true)
    @Override
    public IPage<BiodiversityVo> getBiodiversity(BiodiversitySearchDto dto) {
//        Page<Biodiversity> page = new Page<>(dto.getPageNumber(),dto.getPageSize());
//        QueryWrapper<Biodiversity> wrapper = new QueryWrapper<>();
//        wrapper.eq("kingdom",dto.getKingdom());
//        if (dto.getSearchParam() != null && !dto.getSearchParam().equals("")) {
//            wrapper.and(queryWrapper -> {
//                queryWrapper.like("latin_name",dto.getSearchParam())
//                        .or().like("species",dto.getSearchParam());
//            });
//        }
//        if (dto.getOrgIds() != null && dto.getOrgIds().size() > 0) {
//            wrapper.in("org_id",dto.getOrgIds());
//        }
//        if (dto.getStartTime() != null) wrapper.gt("find_time",dto.getStartTime());
//        if (dto.getEndTime() != null) wrapper.lt("find_time",dto.getEndTime());
//        if (dto.getProtectionLevel() != null && dto.getProtectionLevel().size() > 0) {
//            wrapper.in("protection_level",dto.getProtectionLevel());
//        }
//        if (dto.getIucnLevel() != null && dto.getIucnLevel().size() > 0) {
//            wrapper.in("iucn_level",dto.getIucnLevel());
//        }
//        if (dto.getCitesAppendix() !=null && dto.getCitesAppendix().size() > 0) {
//            wrapper.in("cites_appendix",dto.getCitesAppendix());
//        }
//        wrapper.orderByDesc("create_time");
//        return this.page(page,wrapper);
        Page<BiodiversityVo> page = new Page<>(dto.getPageNumber(),dto.getPageSize());
        IPage<BiodiversityVo> iPage = baseMapper.getBiodiversityList(page, dto);
        return iPage;

    }

    /**
     * 添加生物名录
     * @param dto
     * @return
     * @throws UnsupportedEncodingException
     */
    @Override
    public int addBiodiversity(BiodiversitySaveDto dto) throws UnsupportedEncodingException {
        String username = UserUtil.getCurrentUser();
        int orgId = UserUtil.getCurrentUserOrgId();
        String orgName = UserUtil.getCurrentUserOrgName();
        QueryWrapper<Biodiversity> wrapper = new QueryWrapper<>();
        wrapper.eq("kingdom",dto.getKingdom());
        wrapper.eq("species",dto.getSpecies());
        List<Biodiversity> biodiversities = this.list(wrapper);
        if (biodiversities.size() > 0) return -1;
        Biodiversity biodiversity = new Biodiversity();
        biodiversity.setCreator(username);
        biodiversity.setOrgId(orgId);
        biodiversity.setOrgName(orgName);
        biodiversity.setLatinName(dto.getLatinName());
        biodiversity.setRemark(dto.getRemark());
        biodiversity.setIntroduce(dto.getIntroduce());
        biodiversity.setCitesAppendix(dto.getCitesAppendix());
        biodiversity.setIucnLevel(dto.getIucnLevel());
        biodiversity.setDataSource(dto.getDataSource());
        biodiversity.setProtectionLevel(dto.getProtectionLevel());
        biodiversity.setNumber(dto.getNumber());
        biodiversity.setFindTime(dto.getFindTime());
        biodiversity.setDistribution(dto.getDistribution());
        biodiversity.setSpecies(dto.getSpecies());
        biodiversity.setGenus(dto.getGenus());
        biodiversity.setFamily(dto.getFamily());
        biodiversity.setOrdo(dto.getOrdo());
        biodiversity.setKlasse(dto.getKlasse());
        biodiversity.setPhylum(dto.getPhylum());
        biodiversity.setKingdom(dto.getKingdom());
        biodiversity.setPictureUrl(dto.getPictureUrl());
        return this.baseMapper.insert(biodiversity);
    }

    /**
     * 更新修改生物名录
     * @param biodiversity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateBiodiversity(Biodiversity biodiversity) {
        String username = UserUtil.getCurrentUser();
        User user = userService.getById(username);
        Integer roleId = user.getRoleId();
        Role role = roleService.getById(roleId);
        //如果是普通管理员并且不是本人创建的不能修改
        if (role.getType() == 3) {
            if (!username.equals(biodiversity.getCreator())) return -1;
            return this.baseMapper.updateById(biodiversity);
        }
        List<Integer> orgIds = userService.getOperableOrg(username);
        Integer orgId = biodiversity.getOrgId();
        if (!orgIds.contains(orgId)) return -1;
        return this.baseMapper.updateById(biodiversity);
    }

    /**
     * 删除生物名录
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteBiodiversity(int id) {
        Biodiversity biodiversity = this.baseMapper.selectById(id);
        String username = UserUtil.getCurrentUser();
        User user = userService.getById(username);
        Integer roleId = user.getRoleId();
        Role role = roleService.getById(roleId);
        //如果是普通管理员并且不是本人创建的不能删除
        if (role.getType() == 3) {
            if (!username.equals(biodiversity.getCreator())) return -1;

//            return this.baseMapper.deleteById(biodiversity);//删除名录
        } else {
            List<Integer> orgIds = userService.getOperableOrg(username);
            Integer orgId = biodiversity.getOrgId();
            if (!orgIds.contains(orgId)) return -1;
        }

        //删除生物名录时同步删除实时抓拍归档为该生物的附件，并将实时抓拍回退为未归档状态
        List<BiologyFile> biologyFiles = biologyFileService.list(Wrappers.<BiologyFile>lambdaQuery().eq(BiologyFile::getBiologyName, biodiversity.getSpecies())
                .eq(BiologyFile::getBiologyKingdom, biodiversity.getKingdom()));
        biologyFiles.forEach(biologyFile -> {
            RealtimeShoot realtimeShoot = realtimeShootService.getOne(Wrappers.<RealtimeShoot>lambdaQuery().eq(RealtimeShoot::getFileRelation, biologyFile.getId()));
            if (realtimeShoot != null) {
                biologyFileService.removeById(biologyFile);
                realtimeShootService.update(Wrappers.<RealtimeShoot>lambdaUpdate().eq(RealtimeShoot::getId, realtimeShoot.getId())
                        .set(RealtimeShoot::getFileStatus, 0).set(RealtimeShoot::getFileRelation, null).set(RealtimeShoot::getFileType, null));
            }
        });
        return this.baseMapper.deleteById(biodiversity);
    }

    /**
     * 下载动植物名录导入模板
     *
     * @param response P
     * @param type P
     */
    @Override
    public void downloadTemplate(HttpServletResponse response, Integer type) {
        String biology;
        String templateName;
        String downloadFileName;
        if (type.equals(0)) {
            biology = "动物名录导入模板获取异常！";
            templateName = TEMPLATE_ANIMAL_NAME;
            downloadFileName = "动物名录信息";
        } else {
            biology = "植物名录导入模板获取异常！";
            templateName = TEMPLATE_BOTANY_NAME;
            downloadFileName = "植物名录信息";
        }
        XSSFWorkbook workbook = getWorkbook(biology, templateName);
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 创建机构
        List<Org> orgs = orgService.list();
        String[] names = orgs.stream().map(Org::getName).toArray(String[]::new);
        ExcelUtils.setDropDownBox(sheet, 1, 3, 65535, 3, names, workbook, "机构");
        // 数据来源
        String[] dataSource = {"实地考察", "查阅资料"};
        ExcelUtils.setDropDownBox(1, 65535, 5, 5, sheet, dataSource);
        // 保护等级
        String[] protectionLevel = {"Ⅰ", "Ⅱ", "Ⅲ"};
        ExcelUtils.setDropDownBox(1, 65535, 6, 6, sheet, protectionLevel);
        // IUCN濒危等级
        String[] iucnLevel = {"EN", "VU", "CR"};
        ExcelUtils.setDropDownBox(1, 65535, 7, 7, sheet, iucnLevel);
        // CITES附录
        String[] citesAppendix = {"附录Ⅰ", "附录Ⅱ", "附录Ⅲ"};
        ExcelUtils.setDropDownBox(1, 65535, 8, 8, sheet, citesAppendix);
        ExcelUtils.download(downloadFileName + FILE_SUFFIX, workbook, response);
    }

    /**
     * 批量导入动植物名录信息
     *
     * @param file P
     * @param type P
     * @return R
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importBiology(MultipartFile file, Integer type) {
        InputStream inputStream;
        List<ImportBiodiversityDTO> resultList;
        try {
            inputStream = file.getInputStream();
            ImportParams params = new ImportParams();
            params.setStartSheetIndex(0);
            params.setSheetNum(1);
            params.setTitleRows(0);
            params.setHeadRows(1);
            resultList = ExcelImportUtil.importExcel(inputStream, ImportBiodiversityDTO.class, params);
        } catch (Exception e) {
            e.printStackTrace();
            return "failed";
        }
        if (CollectionUtils.isEmpty(resultList)) {
            return "导入数据为空，请检查填入数据！";
        }
        String username = UserUtil.getCurrentUser();
        // 通过机构名称获取机构id
        List<String> names = resultList.stream().map(ImportBiodiversityDTO::getOrgName).collect(Collectors.toList());
        List<Org> orgList = orgService.list(Wrappers.<Org>lambdaQuery().in(Org::getName, names));
        resultList.forEach(k -> {
            for (Org v : orgList) {
                if (v.getName().equals(k.getOrgName())) {
                    k.setOrgId(v.getId());
                }
            }
            if (StringUtils.isNotBlank(k.getDataSourceName())) {
                // 因为只有1-实地考察  2-查阅资料，所以没有写枚举，如果填写其他统统是“2-查阅资料”
                Integer dataSource = "实地考察".equals(k.getDataSourceName()) ? 1 : 2;
                k.setDataSource(dataSource);
            }
            k.setCreator(username);
            k.setCreateTime(new Date());
            k.setKingdom(type);
        });
        // 去除重复同类下相同名称
        List<String> species = resultList.stream().map(ImportBiodiversityDTO::getSpecies).collect(Collectors.toList());
        List<Biodiversity> list = list(Wrappers.<Biodiversity>lambdaQuery().eq(Biodiversity::getKingdom, type).in(Biodiversity::getSpecies, species));
        if (!CollectionUtils.isEmpty(list)) {
            List<String> repeatSpecies = new ArrayList<>();
            list.forEach(k -> repeatSpecies.add(k.getSpecies()));
            IntStream.range(0, resultList.size()).filter(i ->
                    repeatSpecies.contains(resultList.get(i).getSpecies())).boxed().findFirst().map(i -> resultList.remove((int)i));
        }
        List<Biodiversity> copyLists = ListCopyUtils.copyListProperties(resultList, Biodiversity::new);
        saveBatch(copyLists);
        return "success";
    }

    /**
     * 批量导出动植物名录信息
     *
     * @param response P
     * @param type P
     */
    @Override
    public void exportBiology(HttpServletResponse response, Integer type) {
        // 防止数据量大，可修改接口作分页导出，前端可以把size写到一万以内
        /*Page<Biodiversity> biodiversityPage = new Page<>(1, 10);
        LambdaQueryWrapper<Biodiversity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Biodiversity::getDelFlag, Constants.ZERO);
        wrapper.eq(Biodiversity::getKingdom, type);
        wrapper.orderByDesc(Biodiversity::getCreateTime);*/
        // 查询全部数据
        List<Biodiversity> biodiversities = list(Wrappers.<Biodiversity>lambdaQuery()
                .eq(Biodiversity::getDelFlag, Constants.ZERO)
                .eq(Biodiversity::getKingdom, type)
                .orderByDesc(Biodiversity::getCreateTime));
        if (CollectionUtils.isEmpty(biodiversities)) {
            throw new ServerException("暂无数据导出！");
        }
        /*Page<Biodiversity> page = page(biodiversityPage, wrapper);
        List<Biodiversity> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            throw new ServerException("暂无数据导出！");
        }*/
        List<ExportBiodiversityVO> vos = ListCopyUtils.copyListProperties(biodiversities, ExportBiodiversityVO::new);
        vos.forEach(k -> {
            if (k.getDataSource() != null) {
                String name = k.getDataSource().equals(1) ? "实地考察" : "查阅资料";
                k.setDataSourceName(name);
            }
        });
        String fileName = type.equals(0) ? "动物名录" : "植物名录";
        // 导出
        ExportParams params = new ExportParams();
        params.setSheetName(fileName + "信息");
        params.setHeight((short) 15);
        Workbook workbook = ExcelExportUtil.exportBigExcel(params, ExportBiodiversityVO.class, vos);
        ExcelExportUtil.closeExportBigExcel();
        // 生成文件
        String downloadFileName = fileName + "导出" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 查询生物名称列表
     * @return
     */
    @Override
    public List<Biodiversity> biodiversityNameList() {
        QueryWrapper<Biodiversity> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("species");
        return baseMapper.selectList(queryWrapper);
    }


    /**
     * 获取workbook
     *
     * @return XSSFWorkbook
     */
    private XSSFWorkbook getWorkbook(String exception, String fileName) {
        InputStream inputStream;
        XSSFWorkbook workbook;
        try {
            ClassPathResource classPathResource = new ClassPathResource("excels/" + fileName);
            inputStream = classPathResource.getInputStream();
            workbook = new XSSFWorkbook(inputStream);
        } catch (IOException e) {
            throw new ServerException(exception);
        }
        return workbook;
    }

}
